#include "Game.h"

//default constructor
Game::Game(): startX(4), startY(0), pieceColor(0), nextColor(0), nextX(0), nextY(0),
				maxPieceHeight(4), maxPieceWidth(3), m_input(0), m_playerWantsToQuit(false),
				m_fallTimer(0), m_gameOver(false), m_score(0), m_age(0)
{}

void Game::load()
{
	int mapNo = selectMap();

	switch(mapNo)
	{
	case 1: base.load("base10x15.txt"); startX = 4; break;
	case 2: base.load("base15x15.txt"); startX = 7; break;
	case 3: base.load("base20x20.txt"); startX = 9; break;
	case 4: base.load("base20x25.txt"); startX = 9; break;
	}
	
	nextX = base.getWidth() + 5;
	nextY = 5;
	writeText();
	setPiece();
	m_awardOK = false;
	m_fallRate = FALLRATE_MAX;

}
int Game::selectMap()
{
	gotoxy(15, 1);
	printf("BLOCK PUZZLE LAB");
	gotoxy(15, 2);
	printf("  by Aaron Cole");

	gotoxy(5,5);
	printf("Please select the size of your playing area:");
	gotoxy(15,7);
	printf("1 - 10 x 15 grid");
	gotoxy(15,8);
	printf("2 - 15 x 15 grid");
	gotoxy(15,9);
	printf("3 - 20 x 20 grid");
	gotoxy(15,10);
	printf("4 - 20 x 25 grid");
	int selection = 0;
	while(selection < 1 || selection > 4)
	{
		gotoxy(50,5);
		cin >> selection;
	}
	system("cls");
	return selection;
}
void Game::writeText()
{
	//next piece
	gotoxy(nextX-1, nextY-1);
	printf("NEXT:");
	//score
	gotoxy(nextX-1, (nextY + maxPieceHeight));
	printf("SCORE:");
	//fallrate
	gotoxy(nextX-1, (nextY + maxPieceHeight + 3));
	printf("FALL");
	gotoxy(nextX-1, (nextY + maxPieceHeight + 4));
	printf("RATE:");
	//instructions
	gotoxy(nextX + 8, 1);
	printf("BLOCK PUZZLE LAB");
	gotoxy(nextX + 8, 2);
	printf("  by Aaron Cole");
	gotoxy(nextX + 8, 5);
	printf("CONTROLS:");
	gotoxy(nextX + 8, 6);
	printf("Q - Rotate CCW");
	gotoxy(nextX + 8, 7);
	printf("E - Rotate CW");
	gotoxy(nextX + 8, 8);
	printf("A - Left");
	gotoxy(nextX + 8, 9);
	printf("D - Right");
	gotoxy(nextX + 8, 10);
	printf("S - Down");
	gotoxy(nextX + 8, 12);
	printf("SCORING:");
	gotoxy(nextX + 8, 13);
	printf("5pts for every merged piece");
	gotoxy(nextX + 8, 14);
	printf("25pts for every row cleared");
	gotoxy(nextX + 8, 15);
	printf("100pts for every full board cleared");
	gotoxy(nextX + 8, 17);
	printf("FALL RATE:");
	gotoxy(nextX + 8, 18);
	printf("Decreases by %d every %d s", FALLRATE_RATE, FALLRATE_INTERVAL);
	gotoxy(nextX + 8, 19);
	printf("Slowest Rate: %d ms", FALLRATE_MAX);
	gotoxy(nextX + 8, 20);
	printf("Fastest Rate: %d ms", FALLRATE_MIN);
}
//randomly generate a piece
void Game::randomPieceGenerator()
{
	srand(time(NULL));
	int selection = rand() % 7 + 1; //randomly select a number one through seven
	nextColor = rand() % 14 + 1; //randomly generate a color

	switch(selection)
	{
	case 1: nextPiece.load("piece01.txt"); break;
	case 2: nextPiece.load("piece02.txt"); break;
	case 3: nextPiece.load("piece03.txt"); break;
	case 4: nextPiece.load("piece04.txt"); break;
	case 5: nextPiece.load("piece05.txt"); break;
	case 6: nextPiece.load("piece06.txt"); break;
	case 7: nextPiece.load("piece07.txt"); break;
	}
}
//set a the current piece and
//randomly generate the next piece
void Game::setPiece()
{
	//if a next piece does not exist, generate it nos
	if(nextPiece.isNull())
	{
		randomPieceGenerator();
	}
	//set next piece to current piece
	piece = nextPiece; //operator overloaded
	piece.setXY(startX, startY);
	pieceColor = nextColor;
	//generate a new next piece
	nextPiece.release();
	randomPieceGenerator();
}
//clears the area where the next piece is displayed
void Game::clearNextPieceArea()
{	
	for(int r = nextY; r < nextY + maxPieceHeight; ++r)
	{
		for(int c = nextX; c < nextX + maxPieceWidth; ++c)
		{
			gotoxy(c, r);
			printf(" ");
		}
		printf("\n");
	}
}
void Game::draw()
{
	setcolor(COLOR_GRAY, COLOR_BLACK);
	base.draw();
	setcolor(COLOR_WHITE, COLOR_BLACK);
	gotoxy(nextX, (nextY + maxPieceHeight + 1));
	printf("%d", m_score);
	gotoxy(nextX, (nextY + maxPieceHeight + 5));
	printf("%d", m_fallRate);
	setcolor(pieceColor, COLOR_BLACK);
	piece.draw();
	//clear next piece
	clearNextPieceArea();
	setcolor(nextColor, COLOR_BLACK);
	nextPiece.draw(nextX, nextY);
}

void Game::handleInput(char a_input)
{
	switch(a_input)
	{
	case 27: //esc key
		m_playerWantsToQuit = true;
		break;
	case 'w':
	case 'a':
	case 's':
	case 'd':
	case 'e':
	case 'q':
		m_input = a_input;
		break;
	}
}

bool Game::doesPlayerWantToQuit()
{
	return m_playerWantsToQuit;
}
void Game::release()
{
	setcolor(COLOR_GRAY, COLOR_BLACK);
	gotoxy(0, base.getHeight() + 7);
	base.release();
	piece.release();
	nextPiece.release();
}
//update the current state of the game
//move the piece down every 500ms
//send input to the piece to handle
//check for collision
void Game::update(int a_ms)
{
	int oldX = piece.getX();
	int oldY = piece.getY();

	m_fallTimer += a_ms;
	m_age += a_ms;
	calcFallRate();
	//if(m_input == 0)
	if(m_fallTimer > m_fallRate)
	{
		piece.addY(1);
		m_fallTimer = 0;
	}
	else
	{
		//piece.handleInput() returns true if the piece was merged
		if(piece.handleInput(base, m_input))
		{
			//first see if game is over
			if(!isGameOver())
			{
				//if a piece has merged, set a new piece
				setPiece();
				m_score += 5; //plus 5 points for every new piece
			}
			m_awardOK = true; //it is okay to give the award now
		}
	}

	//if the player is out of the map's boundaries
	if(piece.collisionDetection(base, oldX, oldY, 0))
	{
		//first see if game is over
		if(!isGameOver())
		{
			//if a piece has merged, set a new piece
			setPiece();
			m_score += 5; //plus 5 points for every new piece
		}
		m_awardOK = true; //it is okay to give the award now
	}
	
	eraseRows();
	m_input = 0;
	
	
}
//checks to see if the game is over
//is only called after a collision
bool Game::isGameOver()
{
	//if piece collided on start
	if(piece.getX() == startX && piece.getY() == startY)
	{
		m_gameOver = true;
		return true;
	}
	return false;
}
bool Game::getGameOver()
{
	return m_gameOver;
}
void Game::printGameOver()
{
		setcolor(COLOR_RED, COLOR_BLACK);
		gotoxy((base.getWidth()/2)-4, (base.getHeight()/2));
		printf("GAME OVER");
		gotoxy(0, (base.getHeight()+1));
}
//erase a row after it is full
void Game::eraseRows()
{
	int blockCount = 0;
	int totalCount = 0;
	//for(int r = 0; r < base.getHeight(); ++r)
	for(int r = base.getHeight()-1; r >= 0; r--)
	{
		for(int c = 0; c < base.getWidth(); ++c)
		{
			if(base.getValue(r, c) == '#')
			{
				//increment block count if a value is there
				blockCount++;
				totalCount++;
			}
		}
		//if row is full
		if(blockCount == base.getWidth())
		{
			base.eraseRow(r);
			m_score += 25;//plus 25 points for every row clear
			
		}
		blockCount = 0;

		//if the board is empty
		//m_firstPiece is used to make sure the award is only given once
		if(totalCount == 0 && m_awardOK)//m_award == AWARD_OKAY)
		{
			m_score += 100;//plus 100 points every time the board is completely empty
			m_awardOK = false; //it is not okay to give another award until after a piece
									//has been set and merged
									//this way the score doesn't increase multiple times at once
		}
	}
}
//calculates the fall rate
void Game::calcFallRate()
{
	int seconds = (m_age/1000);
	//increase speed every 30 seconds
	//and if fallRate is greater than 100
	if(seconds%30 && m_fallRate > FALLRATE_MIN)
	{
		int interval = 0;
		interval = seconds/FALLRATE_INTERVAL;
		m_fallRate = FALLRATE_MAX - (interval * FALLRATE_RATE);
	}
}
int Game::getFallRate()
{
	return m_fallRate;
}